package cn.tpshion.vm.handler;

import cn.tpshion.vm.common.constant.BaseConstant;
import cn.tpshion.vm.common.support.FunctionV2;
import cn.tpshion.vm.common.utils.DateUtil;
import io.kubernetes.client.extended.kubectl.Kubectl;
import io.kubernetes.client.extended.kubectl.exception.KubectlException;
import io.kubernetes.client.openapi.ApiClient;
import io.kubernetes.client.openapi.models.*;
import io.kubernetes.client.util.Yaml;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Component;
import java.io.File;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;

@Slf4j
@Component
public class KubectlHandler implements InitializingBean {

    private final Map<Class, FunctionV2<Object, ApiClient, Boolean>> map = new ConcurrentHashMap<>();

    @Override
    public void afterPropertiesSet() {
        map.put(V1Service.class, handleService());
        map.put(V1Deployment.class, handleDeployment());
        map.put(V1Namespace.class, handleNamespace());
        map.put(V1ConfigMap.class, handleConfigMap());
        map.put(V1Secret.class, handleSecret());
        map.put(V1Pod.class, handlePod());
        map.put(V1Ingress.class, handleIngress());
    }

    public void handle(Object obj, ApiClient apiClient){
        FunctionV2<Object, ApiClient, Boolean> function = map.get(obj.getClass());
        if(Objects.nonNull(function)){
            function.apply(obj, apiClient);
        }
    }

    public void handleFile(String filePath, ApiClient apiClient) throws Exception{
        List<Object> list = Yaml.loadAll(new File(filePath));
        list.forEach(i -> handle(i, apiClient));
    }

    private FunctionV2<Object, ApiClient, Boolean> handleNamespace(){
        return (obj, apiClient) -> {
            log.info("handleNamespace");
            try {
                Kubectl.apply(V1Namespace.class).resource((V1Namespace) obj).apiClient(apiClient).execute();
            } catch (KubectlException e) {
                throw new RuntimeException(e);
            }
            return true;
        };
    }

    private FunctionV2<Object, ApiClient, Boolean> handleConfigMap(){
        return (obj, apiClient) -> {
            log.info("handleConfigMap");
            try {
                Kubectl.apply(V1ConfigMap.class).resource((V1ConfigMap) obj).apiClient(apiClient).execute();
            }catch (KubectlException e){
                throw new RuntimeException(e);
            }
            return true;
        };
    }

    private FunctionV2<Object, ApiClient, Boolean> handleSecret(){
        return (obj, apiClient) -> {
            log.info("handleSecret");
            try {
                Kubectl.apply(V1Secret.class).resource((V1Secret) obj).apiClient(apiClient).execute();
            }catch (KubectlException e){
                throw new RuntimeException(e);
            }
            return true;
        };
    }

    private FunctionV2<Object, ApiClient, Boolean> handlePod(){
        return (obj, apiClient) -> {
            log.info("handlePod");
            try {
                Kubectl.apply(V1Pod.class).resource((V1Pod) obj).apiClient(apiClient).execute();
            }catch (KubectlException e){
                throw new RuntimeException(e);
            }
            return true;
        };
    }

    private FunctionV2<Object, ApiClient, Boolean> handleIngress(){
        return (obj, apiClient) -> {
            log.info("handleIngress");
            try {
                Kubectl.apply(V1Ingress.class).resource((V1Ingress) obj).apiClient(apiClient).execute();
            }catch (KubectlException e){
                throw new RuntimeException(e);
            }
            return true;
        };
    }

    private FunctionV2<Object, ApiClient, Boolean> handleDeployment(){
        return (obj, apiClient) -> {
            log.info("handleDeployment");
            try {
                V1Deployment data = (V1Deployment) obj;
                V1PodTemplateSpec template = data.getSpec().getTemplate();
                V1ObjectMeta metadata = template.getMetadata();
                metadata.getLabels().put(BaseConstant.TIME, DateUtil.now(DateUtil.Date_Time_Formatter_No));
                Kubectl.apply(V1Deployment.class).resource(data).apiClient(apiClient).execute();
            }catch (KubectlException e){
                throw new RuntimeException(e);
            }
            return true;
        };
    }

    private FunctionV2<Object, ApiClient, Boolean> handleService(){
        return (obj, apiClient) -> {
            log.info("handleService");
            try {
                Kubectl.apply(V1Service.class).resource((V1Service) obj).apiClient(apiClient).execute();
            }catch (KubectlException e){
                throw new RuntimeException(e);
            }
            return true;
        };
    }
}
